package com.ddwl.gate.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ddwl.common.constant.BaseEnum;
import com.ddwl.common.constant.Constant;
import com.ddwl.common.constant.GateEnum;
import com.ddwl.common.constant.RedisKey;
import com.ddwl.common.exception.CommonException;
import com.ddwl.common.exception.ExceptionCode;
import com.ddwl.common.feign.api.UserApi;
import com.ddwl.common.feign.wx.*;
import com.ddwl.common.service.RedisService;
import com.ddwl.common.util.RandomGenerateUtil;
import com.ddwl.gate.mapper.RegionMapper;
import com.ddwl.gate.util.OssUtil;
import com.ddwl.gate.util.WxaCodeUtil;
import com.ddwl.gate.util.wechat.AesException;
import com.ddwl.gate.util.wechat.WXBizMsgCrypt;
import com.ddwl.schema.bo.gate.GetWxcodeUnlimitBo;
import com.ddwl.schema.bo.gate.wechat.WxCustomMsgBo;
import com.ddwl.schema.bo.gate.wechat.WxTemplateMsgBo;
import com.ddwl.schema.bo.gate.wechat.WxURLSchemeBo;
import com.ddwl.schema.bo.gate.wechat.WxUserInfoBo;
import com.ddwl.schema.bo.order.WxAuthBo;
import com.ddwl.schema.util.DateUtil;
import com.ddwl.schema.vo.base.WxRestVo;
import com.ddwl.schema.vo.gate.wechat.*;
import com.ddwl.schema.vo.user.RegisterBo;
import io.gitee.tooleek.lock.spring.boot.annotation.Lock;
import jodd.util.URLDecoder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author Fu Zhaohui
 * @date 2017/1/3
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WechatService {

    private final RedisService redisService;
    private final RestTemplate restTemplate;
    private final UserApi userApi;
    private final OssUtil ossUtil;
    private final WechatPushRecordService wechatPushRecordService;
    private final WxUserApi wxUserApi;
    private final WxAuthApi wxAuthApi;
    private final WxBaseApi wxBaseApi;
    private final WxWxaApi wxWxaApi;
    private final WxMsgApi wxMsgApi;

    private final RegionMapper regionMapper;

    /**
     * 获取公众号配置
     *
     * @param appId
     * @return
     */
    public WxConfigVo getConfig(String appId, String url) {
        WxConfigVo vo = new WxConfigVo();
        vo.setDebug(true);
        vo.setAppId(appId);
        vo.setTimestamp(System.currentTimeMillis());
        vo.setNonceStr(RandomGenerateUtil.getRandomStr(18));
        vo.setJsApiList(Arrays.asList("checkJsApi", "onMenuShareAppMessage", "openLocation", "getLocation", "chooseWXPay", "scanQRCode"));
        Map<String, Object> signMap = new TreeMap<>();
        signMap.put("jsapi_ticket", redisService.getHashOps().get(RedisKey.WX_TOKEN_KEY.getKey(appId), "ticket"));
        signMap.put("noncestr", vo.getNonceStr());
        signMap.put("timestamp", vo.getTimestamp());
        signMap.put("url", Optional.ofNullable(url).orElse("https://h5.zjddwl.com/"));
        StringBuilder sign = new StringBuilder();
        for (Map.Entry<String, Object> map : signMap.entrySet()) {
            sign.append("&").append(map.getKey()).append("=").append(map.getValue());
        }
        vo.setSignature(SecureUtil.sha1(sign.substring(1)));
        return vo;
    }

    @Lock(leaseTime = 3)
    public WxUserInfoVo getSessionKey(String code, String appId, String product) {
        WxMinAppSessionVo result = getWxMinAppSessionVo(code, appId);

        RegisterBo registerBo = new RegisterBo();
        registerBo.setWxOpenId(result.getOpenid());
        registerBo.setUnionId(result.getUnionid());
        registerBo.setProduct(product);

        WxUserInfoVo wxUserInfoVo = new WxUserInfoVo();
        wxUserInfoVo.setOpenid(result.getOpenid());
        wxUserInfoVo.setSessionKey(result.getSession_key());
        wxUserInfoVo.setUnionId(result.getUnionid());
        wxUserInfoVo.setAppId(appId);
        wxUserInfoVo.setUserAuthVo(userApi.getUserAuthByOpenId(registerBo).getResult());
        Map<String, String> sessionKeyMap = new HashMap<>();
        sessionKeyMap.put("openId", result.getOpenid());
        sessionKeyMap.put("unionId", result.getUnionid());
        redisService.getHashOps().putAll(RedisKey.WX_SESSION_KEY.getKey(wxUserInfoVo.getSessionKey()), sessionKeyMap);
        redisService.getHashOps().getOperations().expire(RedisKey.WX_SESSION_KEY.getKey(wxUserInfoVo.getSessionKey()), 1, TimeUnit.DAYS);
        return wxUserInfoVo;
    }

    public WxUserInfoVo getWbmSessionKey(String code, String appId, String inviteId, String product, String dk) {
        WxMinAppSessionVo result = getWxMinAppSessionVo(code, appId);
        RegisterBo registerBo = new RegisterBo();
        registerBo.setWxOpenId(result.getOpenid());
        registerBo.setUnionId(result.getUnionid());
        registerBo.setProduct(product);
        registerBo.setDk(dk);
        registerBo.setAppId(appId);
        registerBo.setInviteId(inviteId);

        WxUserInfoVo wxUserInfoVo = new WxUserInfoVo();
        wxUserInfoVo.setOpenid(result.getOpenid());
        wxUserInfoVo.setSessionKey(result.getSession_key());
        wxUserInfoVo.setUnionId(result.getUnionid());
        wxUserInfoVo.setAppId(appId);
        wxUserInfoVo.setLoginVo(userApi.checkRegister(registerBo).getResult());
        Map<String, String> sessionKeyMap = new HashMap<>();
        sessionKeyMap.put("openId", result.getOpenid());
        sessionKeyMap.put("unionId", result.getUnionid());
        redisService.getHashOps().putAll(RedisKey.WX_SESSION_KEY.getKey(wxUserInfoVo.getSessionKey()), sessionKeyMap);
        redisService.getHashOps().getOperations().expire(RedisKey.WX_SESSION_KEY.getKey(wxUserInfoVo.getSessionKey()), 1, TimeUnit.DAYS);
        return wxUserInfoVo;
    }

    /**
     * 微信公众号授权登录
     *
     * @param code
     * @param appId
     * @param product
     * @return
     */
    public WxUserInfoVo oauth2(String code, String appId, String product) {
        WxTokenVo result = wxAuthApi.oauth2(appId, redisService.getHashOps().get(RedisKey.WX_ACCOUNT_KEY.getKey(appId), "appSecret"), code, "authorization_code");
        String openId = result.getOpenid();
//        redisService.getHashOps()
        WechatUserInfoVo userInfo = wxUserApi.userInfo(redisService.getHashOps().get(RedisKey.WX_TOKEN_KEY.getKey(appId), "accessToken"), openId);
        RegisterBo registerBo = new RegisterBo();
        registerBo.setAppId(appId);
        registerBo.setWxOpenId(openId);
        registerBo.setUnionId(userInfo.getUnionid());
        registerBo.setProduct(product);
        registerBo.setNickname(userInfo.getNickname());
        registerBo.setSex(Optional.ofNullable(userInfo.getSex()).orElse(1).byteValue());
        registerBo.setAvatar(userInfo.getHeadimgurl());
        registerBo.setCity(userInfo.getCity());
        registerBo.setProvince(userInfo.getProvince());
        registerBo.setRegionId(regionMapper.findCityId(userInfo.getProvince(), userInfo.getCity()));
        WxUserInfoVo wxUserInfoVo = new WxUserInfoVo();
        wxUserInfoVo.setOpenid(openId);
//        wxUserInfoVo.setSessionKey(result.getSession_key());
        wxUserInfoVo.setUnionId(userInfo.getUnionid());
        wxUserInfoVo.setAppId(appId);
        wxUserInfoVo.setLoginVo(userApi.checkRegister(registerBo).getResult());
        return wxUserInfoVo;
    }

    private WxMinAppSessionVo getWxMinAppSessionVo(String code, String appId) {
        String secret = redisService.getHashOps().get(RedisKey.WX_ACCOUNT_KEY.getKey(appId), "appSecret");
        if (!StringUtils.hasText(secret)) {
            throw new CommonException("配置不存在");
        }
        WxMinAppSessionVo result = wxAuthApi.jscode2session(appId, secret, code, "authorization_code");
        if (result.getErrcode() != null) {
            throw new CommonException(result.getErrmsg());
        }
        return result;
    }

    public String getPreAuthCode(String appId) {
        if (!StringUtils.hasText(appId)) {
            appId = "wx63ddac5f996a078a";
        }
        WxAuthBo req = new WxAuthBo(appId);
        String key = RedisKey.WX_TOKEN_KEY.getKey(appId);
        String token = redisService.getHashOps().get(key, "component_access_token");
        if (!StringUtils.hasText(token)) {
            throw new CommonException("授权失败，Token为空");
        }
        WxRestVo resp = restTemplate.postForObject(Constant.WECHAT_PRE_AUTH_URL, req, WxRestVo.class, token);
        return resp.getPre_auth_code();
    }


    public void grantAuth(String appId, String authCode, String mchId) {
        if (!StringUtils.hasText(appId)) {
            appId = "wx63ddac5f996a078a";
        }
        WxAuthBo req = new WxAuthBo(appId, authCode);
        String key = RedisKey.WX_TOKEN_KEY.getKey(appId);
        String token = redisService.getHashOps().get(key, "component_access_token");
        if (!StringUtils.hasText(token)) {
            throw new CommonException("授权失败，Token为空");
        }
        WxRestVo resp = restTemplate.postForObject(Constant.WECHAT_AUTH_QUERY_URL, req, WxRestVo.class, token);
        log.info("auth success : " + JSON.toJSONString(resp));
        WxGrantVo auth = resp.getAuthorization_info();
        String authAppId = auth.getAuthorizer_appid();
        Map<String, String> entryMap = new HashMap<>(10);
        entryMap.put("component_appid", appId);
        entryMap.put("authorizer_appid", authAppId);
        entryMap.put("authorizer_access_token", auth.getAuthorizer_access_token());
        entryMap.put("authorizer_refresh_token", auth.getAuthorizer_refresh_token());
        entryMap.put("timestamp", DateUtil.getCurrDate(DateUtil.DATE_TIME_FORMAT));
        entryMap.put("mchId", mchId);
        entryMap.put("expire", auth.getExpires_in() + "");
        key = RedisKey.GRANT_WX_TOKEN_KEY + authAppId;
        redisService.getHashOps().putAll(key, entryMap);
    }


    public WxRestVo getAuthInfo(String appId) {
        String key = RedisKey.GRANT_WX_TOKEN_KEY.getKey(appId);
        Map<String, String> entryMap = redisService.getHashOps().entries(key);
        if (entryMap == null) {
            throw new CommonException(ExceptionCode.DATA_NOT_EXISTS);
        }
        String component_appid = entryMap.get("component_appid");
        String token = redisService.getHashOps().get(RedisKey.WX_TOKEN_KEY + component_appid, "component_access_token");
        if (!StringUtils.hasText(token)) {
            throw new CommonException("授权失败，Token为空");
        }
        WxAuthBo req = new WxAuthBo();
        req.setComponent_appid(component_appid);
        req.setAuthorizer_appid(appId);
        return restTemplate.postForObject(Constant.WECHAT_AUTH_INFO_QUERY_URL, req, WxRestVo.class, token);
    }

    public byte[] unlimitAppCode(GetWxcodeUnlimitBo req, String appId) {
        byte[] bytes = restTemplate.postForObject(Constant.WECHAT_UNLIMIT_APP_CODE, req, byte[].class, getAccessToken(appId));
        return bytes;
    }

    /**
     * 微信公众号推送消息
     *
     * @param
     */
    public WxRestVo tempMessagePush(WxTemplateMsgBo template) {
        String token = redisService.getHashOps().get(RedisKey.WX_TOKEN_KEY.getKey(BaseEnum.WxAppId.WBM_OFFICE.getCode()), "accessToken");
        log.info("token: [{}]", token);
        log.info("template: [{}]", JSON.toJSONString(template));
        String result = restTemplate.postForObject(Constant.WECHAT_TEMPLATE_URL, template, String.class, token);
        log.info("result: [{}]", result);
        WxRestVo restVo = JSONObject.parseObject(result, WxRestVo.class);
        wechatPushRecordService.save(template.getTouser(), template.getTemplate_id(), JSON.toJSONString(template), restVo.getErrcode(), restVo.getErrmsg(), restVo.getMsgid());
        return restVo;
    }

    public WechatUserInfoListVo batchGetWxUserInfo(String next_openid) {
        WechatUserInfoListVo userInfoListVo = new WechatUserInfoListVo();
        userInfoListVo.setUser_info_list(new ArrayList<>());
        WxUserOpenIdVo wuoVo = getWechatUserOpenId(next_openid);
        userInfoListVo.setNext_openid(wuoVo.getNext_openid());
        if (StrUtil.isNotEmpty(wuoVo.getNext_openid())) {
            WxUserInfoBo bo = new WxUserInfoBo();
            bo.setUser_list(new ArrayList<>());
            WxUserOpenIdVo.OpenIdVo openIdData = wuoVo.getData();
            List<String> openidList = openIdData.getOpenid();
            for (int i = 0; i < openidList.size(); i++) {
                if (bo.getUser_list().size() != 0 && bo.getUser_list().size() % 100 == 0) {
                    List<WechatUserInfoVo> userInfoLists = wxUserInfoList(bo);
                    userInfoListVo.getUser_info_list().addAll(userInfoLists);
                    bo.setUser_list(new ArrayList<>());
                }
                WxUserInfoBo.UserList ul = bo.new UserList();
                ul.setOpenid(openidList.get(i));
                bo.getUser_list().add(ul);
                openidList.remove(i);
                i--;
            }
            if (!CollectionUtils.isEmpty(bo.getUser_list())) {
                List<WechatUserInfoVo> userInfoLists = wxUserInfoList(bo);
                userInfoListVo.getUser_info_list().addAll(userInfoLists);
            }
        }
        log.info("userInfoListSize: [{}]", userInfoListVo.getUser_info_list().size());
        return userInfoListVo;
    }

    private List<WechatUserInfoVo> wxUserInfoList(WxUserInfoBo bo) {
        String token = redisService.getHashOps().get(RedisKey.WX_TOKEN_KEY.getKey(BaseEnum.WxAppId.WBM_OFFICE.getCode()), "accessToken");
        log.info("token: [{}]", token);
        String result = restTemplate.postForObject(Constant.WECHAT_USERINFO_BATCH_URL, bo, String.class, token);
        log.info("result: [{}]", result);
        WechatUserInfoListVo vo = JSONObject.parseObject(result, WechatUserInfoListVo.class);
        return vo.getUser_info_list();
    }


    private WxUserOpenIdVo getWechatUserOpenId(String nextOpenId) {
        String token = redisService.getHashOps().get(RedisKey.WX_TOKEN_KEY.getKey(BaseEnum.WxAppId.WBM_OFFICE.getCode()), "accessToken");
        log.info("token: [{}]", token);
        String result = restTemplate.getForObject(Constant.WECHAT_USER_OPENID_URL, String.class, token, nextOpenId);
        log.info("result: [{}]", result);
        return JSONObject.parseObject(result, WxUserOpenIdVo.class);
    }

    public WechatUserInfoVo getWechatUserInfo(String openId) {
        String token = redisService.getHashOps().get(RedisKey.WX_TOKEN_KEY.getKey(BaseEnum.WxAppId.WBM_OFFICE.getCode()), "accessToken");
        log.info("token: [{}]", token);
        String result = restTemplate.getForObject(Constant.WECHAT_USERINFO_URL, String.class, token, openId);
        log.info("result: [{}]", result);
        return JSONObject.parseObject(result, WechatUserInfoVo.class);
    }

    public String verifyUrl(String appId, String signature,
                            String timestamp, String nonce, String echostr) throws AesException {
        String key = RedisKey.WX_TOKEN_KEY.getKey(appId);
        String token = redisService.getHashOps().get(key, "token");
        String encodingAesKey = redisService.getHashOps().get(key, "encodingAesKey");
        WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
        pc.verifyUrl(signature, timestamp, nonce, echostr);
        return echostr;
    }

    public void handleMsg(String appId, HttpServletRequest request, String msg_signature,
                          String timestamp, String nonce) throws IOException, ParserConfigurationException, SAXException, AesException {
        StringBuilder sb = new StringBuilder();
        BufferedReader in = request.getReader();
        String line;
        while ((line = in.readLine()) != null) {
            sb.append(line);
        }
        String replyMsg = sb.toString();
        log.info("###### 接收数据：" + replyMsg);
        if (!StringUtils.hasText(replyMsg)) {
            return;
        }
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        StringReader sr = new StringReader(replyMsg);
        InputSource is = new InputSource(sr);
        Document document = db.parse(is);
        Element root = document.getDocumentElement();
        NodeList appIdNode = root.getElementsByTagName("AppId");
        if (appIdNode != null && appIdNode.item(0) != null) {
            appId = appIdNode.item(0).getTextContent();
        }
        if (!StringUtils.hasText(appId)) {
            return;
        }
        String key = RedisKey.WX_TOKEN_KEY.getKey(appId);
        String token = redisService.getHashOps().get(key, "token");
        String encodingAesKey = redisService.getHashOps().get(key, "encodingAesKey");
        if (!StringUtils.hasText(encodingAesKey)) {
            return;
        }
        WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
        String result = pc.decryptMsg(msg_signature, timestamp, nonce, replyMsg);
        log.info("###### 解密后明文: " + result);
        sr = new StringReader(result);
        is = new InputSource(sr);
        document = db.parse(is);
        root = document.getDocumentElement();
        NodeList params = root.getChildNodes();
        Map<String, String> nodeMap = new HashMap<>(params.getLength());
        for (int i = 0; i < params.getLength(); i++) {
            Node node = params.item(i);
            String nodeName = node.getNodeName();
            if (nodeName.startsWith("#")) {
                continue;
            }
            nodeMap.put(nodeName, node.getTextContent());
        }
        String InfoType = nodeMap.get("InfoType");
        if (StringUtils.hasText(InfoType)) {
            switch (InfoType) {
                case "component_verify_ticket":
                    String ComponentVerifyTicket = nodeMap.get("ComponentVerifyTicket");
                    redisService.getHashOps().put(key, "component_verify_ticket", ComponentVerifyTicket);
                    redisService.getHashOps().put(key, "ticket_timestamp", DateUtil.getCurrDate(DateUtil.DATE_TIME_FORMAT));
                    break;

                case "authorized":
                    String AuthorizerAppid = nodeMap.get("AuthorizerAppid");
                    String authAppIdkey = RedisKey.GRANT_WX_TOKEN_KEY + AuthorizerAppid;
                    redisService.getHashOps().put(authAppIdkey, "authorization_code", nodeMap.get("AuthorizationCode"));
                    redisService.getHashOps().put(authAppIdkey, "authorization_timestamp", DateUtil.getCurrDate(DateUtil.DATE_TIME_FORMAT));
                    break;
            }
        }
        String event = nodeMap.get("Event");
        if (StringUtils.hasText(event)) {
            switch (event) {
                case "unsubscribe":
                    break;
                case "subscribe":
                    String wxToken = redisService.getHashOps().get(RedisKey.WX_TOKEN_KEY.getKey(appId), "accessToken");
                    WechatUserInfoVo userInfo = wxUserApi.userInfo(wxToken, nodeMap.get("FromUserName"));
                    log.info("用户信息 =》 {}", JSON.toJSONString(userInfo));
                    try {
                        RegisterBo registerBo = new RegisterBo();
                        registerBo.setAppId(appId);
                        registerBo.setWxOpenId(userInfo.getOpenid());
                        registerBo.setUnionId(userInfo.getUnionid());
                        registerBo.setProduct(BaseEnum.ProductEnum.WBM_OFFICE.getName());
                        registerBo.setNickname(userInfo.getNickname());
                        registerBo.setSex(Optional.ofNullable(userInfo.getSex()).orElse(1).byteValue());
                        registerBo.setAvatar(userInfo.getHeadimgurl());
                        registerBo.setCity(userInfo.getCity());
                        registerBo.setProvince(userInfo.getProvince());
                        registerBo.setRegionId(regionMapper.findCityId(userInfo.getProvince(), userInfo.getCity()));
                        userApi.checkRegister(registerBo);
                    } catch (Exception e) {
                        log.error("添加用户失败", e);
                    }
                    WxCustomMsgBo msgBo = new WxCustomMsgBo();
                    msgBo.setTouser(userInfo.getOpenid());
                    msgBo.setMsgtype("text");
                    msgBo.setText(msgBo.new Text("到五八马来选自己心仪的礼品吧<a href=\"http://www.qq.com\" data-miniprogram-appid=" + BaseEnum.WxAppId.WBM.getCode() + " data-miniprogram-path=" + GateEnum.WbmMinAppPage.SHOP_INDEX.getPath() + ">点击进入五八马</a>"));
                    wxMsgApi.customSend(wxToken, msgBo);
                    break;
            }
        }
    }

    public String getAccessToken(String appId) {
        String secret = redisService.getHashOps().get(RedisKey.WX_ACCOUNT_KEY.getKey(appId), "appSecret");
        WxRestVo wxRestVo = wxBaseApi.token(appId, secret, "client_credential");
        return wxRestVo.getAccess_token();
    }

    public String wxaCodeUnlimitUrl(GetWxcodeUnlimitBo body, String appId, String filePath) {
        String base64Str = Base64.encodeBase64String(unlimitAppCode(body, appId));
        return ossUtil.base64UploadFileThenReturn(base64Str, filePath);
    }

    public String customizeLogoWxaCodeUrl(GetWxcodeUnlimitBo body, String appId, String filePath, String fileName, int width, int height) {
        File wxaCodeFile = null;
        File logoFile = null;
        File newWxaCode = null;
        fileName = URLDecoder.decode(fileName, "UTF-8");
        try {
            wxaCodeFile = File.createTempFile("wxaCode", ".png");
            logoFile = File.createTempFile("logo", ".png");
            newWxaCode = File.createTempFile("newWxaCode", ".png");
        } catch (IOException e) {
            log.error("自定义logo小程序码创建出错：{}", e.getMessage());
        }
        WxaCodeUtil.byteToImage(wxaCodeFile, unlimitAppCode(body, appId));
        ossUtil.getOSSObject(logoFile, fileName);
        String base64Str = WxaCodeUtil.changeLogo(wxaCodeFile, logoFile, newWxaCode, width, height);
        String url = ossUtil.base64UploadFileThenReturn(base64Str, filePath);
        wxaCodeFile.delete();
        logoFile.delete();
        newWxaCode.delete();
        return url;
    }

    public String getShopWxaCode(GetWxcodeUnlimitBo body, String appId, String fileName, int width, int height) {
        File wxaCodeFile = null;
        File logoFile = null;
        File newWxaCode = null;
        File finalFile = null;
        String base64Str = "";
        try {
            wxaCodeFile = File.createTempFile("wxaCode", ".png");
            logoFile = File.createTempFile("logo", ".png");
            newWxaCode = File.createTempFile("newWxaCode", ".png");
            finalFile = File.createTempFile("finalFile", ".png");
        } catch (IOException e) {
            log.error("获取店铺小程序码出错：{}", e.getMessage());
        }
        if (StrUtil.isNotEmpty(fileName)) {
            fileName = URLDecoder.decode(fileName, "UTF-8");
            WxaCodeUtil.byteToImage(wxaCodeFile, unlimitAppCode(body, appId));
            ossUtil.getOSSObject(logoFile, fileName);
            WxaCodeUtil.changeLogo(wxaCodeFile, logoFile, newWxaCode, width, height);
            base64Str = WxaCodeUtil.compoundShopCodeImage(finalFile, newWxaCode);
        } else {
            WxaCodeUtil.byteToImage(wxaCodeFile, unlimitAppCode(body, appId));
            base64Str = WxaCodeUtil.compoundShopCodeImage(finalFile, wxaCodeFile);
        }
        wxaCodeFile.delete();
        logoFile.delete();
        newWxaCode.delete();
        finalFile.delete();
        return base64Str;
    }

    public String getUserShareCode(GetWxcodeUnlimitBo body, String appId) {
        return Base64.encodeBase64String(unlimitAppCode(body, appId));
    }

    public String generateScheme(String appId, WxURLSchemeBo bo) {
        WxSchemeVo vo = wxWxaApi.generateScheme(getAccessToken(appId), bo);
        return vo.getOpenlink();
    }

    public String getOSSBase64(String fileName) {
        return ossUtil.getOSSBase64(fileName);
    }

}
